10. NumPy 中的转置
转置
在 NumPy 中获得矩阵的转置非常容易。只需访问其 T
属性即可。还有一个 transpose()
函数也可以返回同样的结果,但是你很少看到它的使用,因为输入 T
的方法要简单得多。:)
例如:
m = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
m
# 显示以下结果:
# array([[ 1, 2, 3, 4],
# [ 5, 6, 7, 8],
# [ 9, 10, 11, 12]])
m.T
# 显示以下结果:
# array([[ 1, 5, 9],
# [ 2, 6, 10],
# [ 3, 7, 11],
# [ 4, 8, 12]])
NumPy 在进行转置时不会实际移动内存中的任何数据 - 只是改变对原始矩阵的索引方式 - 所以是非常高效的。
但是,这也意味着你要特别注意修改对象的方式,因为它们共享相同的数据。例如,对于上面同一个矩阵 m
,我们来创建一个新的变量 m_t
来存储 m
的转置。然后看看如果我们修改 m_t
中的值,会发生什么:
m_t = m.T
m_t[3][1] = 200
m_t
# 显示以下结果:
# array([[ 1, 5, 9],
# [ 2, 6, 10],
# [ 3, 7, 11],
# [ 4, 200, 12]])
m
# 显示以下结果:
# array([[ 1, 2, 3, 4],
# [ 5, 6, 7, 200],
# [ 9, 10, 11, 12]])
注意它是如何同时修改转置和原始矩阵的!这是因为它们共享相同的数据副本。所以记住,将转置视为矩阵的不同视图,而不是完全不同的矩阵。
实际用例
我不想过多讲解关于神经网络的细节,因为你还没有学到它们,但是有一个地方你差不多肯定会用到转置,或者至少考虑使用转置。
假设你有以下两个矩阵,称为 inputs
和 weights
,
inputs = np.array([[-0.27, 0.45, 0.64, 0.31]])
inputs
# 显示以下结果:
# array([[-0.27, 0.45, 0.64, 0.31]])
inputs.shape
# 显示以下结果:
# (1, 4)
weights = np.array([[0.02, 0.001, -0.03, 0.036], \
[0.04, -0.003, 0.025, 0.009], [0.012, -0.045, 0.28, -0.067]])
weights
# 显示以下结果:
# array([[ 0.02 , 0.001, -0.03 , 0.036],
# [ 0.04 , -0.003, 0.025, 0.009],
# [ 0.012, -0.045, 0.28 , -0.067]])
weights.shape
# displays the following result:
# (3, 4)
我在这里不会讲解它们的用途,因为你稍后都会学到,但是最终你会想要获得这两个矩阵的矩阵乘积。
如果你像现在这样去尝试,会获得一个错误:
np.matmul(inputs, weights)
# 显示以下错误:
# ValueError: shapes (1,4) and (3,4) not aligned: 4 (dim 1) != 3 (dim 0)
如果你学了矩阵乘法课,那应该见过这个错误。它报告说形状不兼容,因为左边矩阵的列数 4
不等于右边矩阵的行数 3
。
所以这不可行,但是注意,如果你获取 weights
矩阵的转置,它会:
np.matmul(inputs, weights.T)
# 显示以下结果:
# array([[-0.01299, 0.00664, 0.13494]])
如果你获取 inputs
的转置,并调换它们的顺序也可以,就像我们在视频中展示的那样:
np.matmul(weights, inputs.T)
# 显示以下结果:
# array([[-0.01299],#
# [ 0.00664],
# [ 0.13494]])
这两个答案是彼此的转置,所以你使用的乘法只取决于你想要的输出的形状。